Skip to content

Fun experiment: an explorable toroidal world - #139

Open
genixpro wants to merge 41 commits into
masterfrom
codex/toroidal-world
Open

Fun experiment: an explorable toroidal world#139
genixpro wants to merge 41 commits into
masterfrom
codex/toroidal-world

Conversation

@genixpro

@genixpro genixpro commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Ready for review, with ongoing integration checks against master.

A rendering experiment that makes Glob2’s wrapping map visible as a live 3D torus. G explicitly switches between regular 2D and the optional torus view. Arrow keys, screen edges, the minimap and middle-drag navigate within the current mode; the wheel zooms within 3D. By default, ordinary scrolling never folds the map or snaps back. Main-menu Settings → General Settings → Automatic torus view enables gradual folding while scrolling and a quick return after movement stops; G keeps the overview open. The preference is saved locally and is inactive with software rendering. Normal 2D retains its viewport renderer, without full-world texture captures or torus mesh updates.

Following Giszmo’s feedback, this incorporates the feature changes from feat/torus-pan through b838f8de, with attribution to Bob. Both map axes slide around a ring whose orientation stays fixed. The star field follows horizontal navigation only: vertical movement rolls the map around the tube without tilting the sky. The camera tilt follows the playable area’s aspect ratio and favors the front-facing landscape over keeping the torus hole visible. The original screen-center map position stays anchored throughout the transition. Wide maps use a flatter view; fitting favors this foreground focus and can crop the distant rim. Wheel zoom allows a closer view. Playtesting favored explicit mode switching as the default; automatic folding remains available as an opt-in preference. Both modes use the same renderer and performance fixes.

Rendering and interaction

  • Ring and tube radii follow map aspect ratio, with isothermal texture coordinates keeping tiles locally square on the surface. Tall maps make fat rings and wide maps make thin rings; tile area still varies around the tube. Camera fitting, clouds and picking share the geometry.
  • Camera and input state live in TorusView.cpp; OpenGL drawing and resource ownership live in TorusViewRender.cpp.
  • Terrain, units, buildings, shadows, fog of war, and previews reuse the existing map renderer. Clouds float on a separate surface and settle as the map flattens; cloud texture coordinates account for the map capture origin and texel centers.
  • The shared building renderer draws the wrapped copies intersecting the view. Previously, its 16-tile viewport margin could move buildings outside a full-world capture. The correction also applies to software rendering.
  • Unit drawing uses the visible wrapped map cell from the existing traversal. This fixes explorers and ground units being misplaced near full-world texture edges and preserves distinct copies at seams.
  • Picking uses the rendered triangles, with double-precision barycentric calculations for narrow triangles in shallow views. Explicit view toggles finish active painting gestures; automatic transitions hold their projection during pointer gestures. Reload clears camera, picking, and GPU state. Middle-button release is handled before modal event processing.
  • Saved keyboard layouts gain missing default actions only when their keys do not conflict with custom bindings or sequence prefixes.

Software rendering remains supported, including builds with opengl=0 and startup with GPU mode requested. Unsupported configurations retain 2D. Camera state is not saved or sent over the network.

Large-map performance

Profiling Oazis (256 × 256) on an Apple M3 identified redundant full-world cloud generation, individual resource sprite draws, and per-sprite GPU state changes in the batching path. The capture now computes shadows only, with overview cloud sampling bounded to 128 cells per world axis. Variable-size resource frames use a padded atlas, and queued sprite draws set GPU state at batch submission. Normal 2D retains native detail and software rendering.

The overview texture cap is 4096 pixels per axis, reducing the 256 × 256 map’s color texture from 256 MiB to 64 MiB. The live map still refreshes every rendered frame. In 100-frame rendering benchmarks with GPU completion included, the torus improved from about 130 ms to 12–16 ms per frame with clouds. These measurements exclude simulation, HUD drawing and frame pacing. The optimized build has also been playtested locally.

Validation

Resource atlas comparisons cover every frame at three scales and two opacity levels, with zero pixel difference on macOS. A repeatable loaded-game performance benchmark is included. Synthetic 64 × 128, 512 × 64, 64 × 512 and square maps cover proportions, fitting, picking and map-dimension cache changes. The map-proportioned geometry measured 16.64 ms median / 17.87 ms p95 with clouds in a 150-frame Oazis run on the M3; desktop load affects these rendering-only measurements.

Local macOS validation covers OpenGL and software-only release builds, loaded-game rendering in both modes, cloud transitions, wrapped navigation, picking, explicit mode transitions, inactive torus controls during 2D navigation, explorer positions across viewport and atlas seams, automatic-mode timing and pinning, option persistence, keyboard conflicts, and repeated resource teardown/recreation. Geometry, picking, cloud-field and building-wrap tests pass AddressSanitizer/UndefinedBehaviorSanitizer.

CI builds Linux 22.04/24.04 and MinGW-w64 game/server targets and runs the standalone tests. Linux additionally exercises the loaded game through Mesa/Xvfb and SDL software rendering, builds without OpenGL, and checks startup and rendering with GPU mode requested. See the current PR checks for results on the latest commit.

Earlier demo

This recording shows the original manual camera experiment. It predates the fixed-axis scrolling behavior and rendering corrections above.

torus-demo-final.mp4

Scope and limitations

This PR tracks master through merge commits. The AI trainer/refactoring and fullscreen-scaling PRs have now landed in master and are included through that base. The torus is adapted to the new GUI/render modules, viewer state and pending building positions. Conflicts and CI will continue to be maintained during review. Giszmo's native Wayland setup still needs playtesting to verify the combined behavior.

Compatibility OpenGL with shaders and framebuffer objects is required for 3D. Large maps may downsample at the 4096-pixel atlas cap and can cost more than ordinary 2D. Tile size varies around the tube and perspective foreshortens tiles, especially near the inner opening. Units/buildings remain sprites on the surface; unit picking uses map cells. Native Windows/Linux visual and broader gameplay testing remain useful.

Build instructions, architecture, tests and limitations.

@genixpro

genixpro commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author
torus-demo-web.mp4
torus-overview unfolding map-2d

@genixpro

genixpro commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author
torus-demo-final.mp4
frame-14 frame-12 frame-0

@genixpro
genixpro requested review from Giszmo and kylelutze and removed request for Giszmo September 5, 2026 01:07
@genixpro
genixpro marked this pull request as ready for review September 5, 2026 01:44
@genixpro

genixpro commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

@Giszmo can we split the difference and make the torus zoom-out and snap-back mode configurable? I've found it very awkward in my testing

Keep explicit mode switching as the default. Add a persistent in-game option for gradual movement-triggered folding and quick return, with G pinning and pointer gesture protection. Preserve software rendering and keep the PR based on master.
@genixpro

genixpro commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

@Giszmo The two navigation styles are now supported through Settings → General Settings → Automatic torus view from the main menu. It is off by default, preserving explicit G switching. Enabling it gives gradual folding while scrolling and a quick return after movement stops; G keeps the overview open. The preference is saved locally, and automatic transitions wait for selection/painting gestures to finish. Software rendering stays in 2D.

Further profiling on a 256 × 256 map also exposed redundant cloud generation and sprite submission overhead. The rendering benchmark improved from about 130 ms to 12–16 ms per frame on the M3, with the map still refreshing every frame. GPU and software checks pass, including pixel comparisons for the resource batching change.

Thanks for explaining the Wayland failure. I understand that it belongs to master’s fullscreen scaling rather than this feature. I’d like to keep this PR independent and focused while #129 and #132 are still pending, rather than coupling it to that larger dependency chain. This leaves the Wayland issue outstanding here until the separate scaling work lands.

@Giszmo

Giszmo commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

You could also help make those other improvements land ;)

@Giszmo Giszmo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NACK while we fix bugs. Don't make the revival harder than it is with fun experiments. I fell for the temptation to play with that torus view and would advocate to switch it on by default but merging 3k LOC in a major refactoring effort is counter productive.

@Giszmo

Giszmo commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Try your torus world with extreme map geometries. Out of the box a 64x128 map looks like this here:

image

For comparison, a 512x64 looks like this:

Screenshot From 2026-09-06 01-36-01

@genixpro
genixpro marked this pull request as draft September 6, 2026 02:20
@genixpro

genixpro commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

@Giszmo I've moved this PR to draft for now and merged current master, including the refactoring and fullscreen-scaling work now that those PRs have landed. The torus integration follows the new GUI/render modules and separate viewer and pending-building state. Explicit G switching remains the default, with automatic folding off by default in the main Settings menu.

The integration also caught a nearest-neighbour sampling mismatch between standalone and atlas resource sprites; that is fixed, with identical pixels at native, reduced and enlarged scales. Local OpenGL and software-only build/rendering checks pass, as do the broader test executables and the selection/terrain regressions. The 256 × 256 rendering benchmark remains about 12 ms per frame with clouds on the M3 (rendering only).

I'll keep the draft current with master and resolve integration conflicts as they arise. Native Wayland playtesting of the combined changes is still needed.

@genixpro

genixpro commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

@Giszmo Thanks for the rectangular-map examples. Addressed in 1016f0b: the torus ring/tube proportions now follow the map dimensions, with isothermal texture coordinates so tiles stay locally square on the surface. Wide maps produce thinner rings and tall maps produce fatter ones. Tile area still changes around the tube, and perspective still foreshortens it.

The geometry is shared by rendering, clouds and picking; the fitting/mesh caches also account for map aspect ratio. Mesh size stays fixed. I checked 64 × 128, 512 × 64, 64 × 512 and square terrain grids, including transitions, wrapped picking and changing map dimensions. OpenGL and software-only builds/rendering pass, as do geometry/picking tests under ASan/UBSan. The 256 × 256 Oazis rendering benchmark measured 16.64 ms median with clouds in this run on the M3 (rendering only).

Keeping this in draft and current with master while the revival work settles. Manual mode switching remains the default, automatic folding remains opt-in in the main Settings menu, and native Wayland playtesting is still outstanding.

@genixpro

genixpro commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Visual evidence for the map-proportion fix in 1016f0b. These are actual OpenGL renders using the benchmark’s synthetic checkerboard terrain, which makes tile proportions easier to compare. Dimensions below are map width × height.

Tall map — 64 × 128 Square map — 128 × 128 Wide map — 512 × 64
64 × 128: fat torus 128 × 128: square-map torus 512 × 64: thin ring

Tall maps produce a fatter tube and wide maps a thinner ring. The visual priority is square-looking tiles in the visible, camera-facing region. The mapping preserves local surface proportions; perspective still compresses tiles as the surface turns away, and tile area varies around the tube. Distortion at the sides and inner opening is less important than readability in the main visible region. Click an image for full resolution.

To reproduce, build torus-render-benchmark and run with GLOB2_BENCH_SIZE=64x128, 128x128, or 512x64, and GLOB2_BENCH_CAPTURE=/tmp/torus.ppm. These images illustrate the geometry; the automated rendering, picking and software-path validation is described in the preceding comment.

Integrate master through 95de302, preserving torus rendering, software fallback and sprite batching across the identifier cleanup and fullscreen letterboxing. Keep the optional torus setting alongside the new game-speed controls. Use a numerically resolvable finite-difference interval in the tile-proportion test on non-FMA platforms without relaxing its tolerance.
@genixpro

genixpro commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Maintenance update: merged master through 95de302 in 3cc46b1 and resolved the conflicts with the identifier cleanup, fullscreen letterboxing, and new game-speed settings. Both settings are available without overlapping; manual G switching remains the default and automatic torus folding stays off by default.

The Linux/Windows failure on 1016f0b was a numerically unstable finite-difference test on the very small inner wall of a tall-map torus. I reproduced it locally with fused multiply-add disabled and increased the sampling interval without relaxing the accuracy threshold or changing the renderer. Geometry and picking now pass locally with FMA disabled and with ASan/UBSan.

OpenGL and software-only builds/rendering, software-only startup with GPU mode requested, rectangular-map fitting/picking, fullscreen aspect-ratio checks, game-speed controls/playback, and the selection, terrain, wrapped-building, entering-unit and savegame regressions pass locally. Resource-atlas comparisons still have zero differing pixels. The latest 256 × 256 rendering-only benchmark measured 11.4 ms median with clouds on the M3. CI is running for the new merge; the PR remains draft, and native Wayland playtesting is still outstanding.

@stephanemagnenat

stephanemagnenat commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Note/question: did you consider rendering the units in 3D? The repository has the 3D models of the globules in Blender.

Also, we could try to see if there exist tools to create 3D models from 2D images, for the other elements.

That could create a small world/little planet style.

Of course, this would make the two rendering paths (2D and torus) very different and thus increase the load time if done naively, but probably some on-demand loading could be done.

@Giszmo

Giszmo commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Note/question: did you consider rendering the units in 3D? The repository has the 3D models of the globules in Blender.

That would be a separate PR but of course, wrapping a 3D world into a torus might have extra challenges compared to the mere 2D wrapping.

Visual evidence for the map-proportion fix

That checkered torus images are a great way to visualize the problem. I would tilt the torus though to fill the screen's aspect ratio or even allow it to crop left and right to focus more on the front facing landscape.

@stephanemagnenat

Copy link
Copy Markdown
Contributor

wrapping a 3D world into a torus might have extra challenges compared to the mere 2D wrapping.

Without thinking too much about it, I do not expect to be too hard to transform an (x, y, z) coordinate (for z << x or y) onto the torus coordinates. I imagine we can do that on the shader itself. Because you basically take (x, y), map it on the torus 3D point, then multiply z with the unitary normal at that point, and voilà.

@genixpro

genixpro commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

@Giszmo Addressed the tilt suggestion in 0e4524d. The camera now fits the torus silhouette to the playable area’s aspect ratio instead of forcing a steep view to keep the hole visible. This gives the front-facing landscape more room; wheel zoom still allows a closer view with cropped sides. The local square-tile mapping is unchanged.

Updated actual renders, with map width × height:

64 × 128 128 × 128 512 × 64
Tall map, foreground-focused camera Square map, foreground-focused camera Wide map, viewport-fitting camera

Shallow angles also exposed precision loss when picking narrow projected triangles. The barycentric calculation now uses double precision, with coverage across portrait and wide windows, map shapes, and transitions. OpenGL and software-only builds/rendering, software-only startup with GPU requested, ASan/UBSan geometry/picking checks with FMA disabled, the terrain regression and all 158 CppUnit tests pass locally. The 256 × 256 rendering-only benchmark measured about 15.4 ms median with clouds on the M3 in this run.

Master is merged through b47c7d2 in the separate merge commit e155753. The previous Linux/Windows CI run passed; new checks are running. Keeping the PR draft and automatic folding off by default. Agreed that 3D unit models belong in a separate PR; this one continues to reuse the sprite renderer.

@Giszmo

Giszmo commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Can you render how 64x512 would look? I'd tilt the 512x64 much flatter. When you zoom out, you still care about what was the center of screen and in this case it drifts off very far.

I assume the 64x512 case would need an extreme ellipsis rotated around the center instead of a circle.

@genixpro
genixpro marked this pull request as ready for review September 8, 2026 13:18
Integrate master through f50ab27, retaining native Linux runners, compiler selection, torus regression checks and upstream compiler caching and tests. Reuse client objects for the team statistics harness so its link-only environment does not duplicate compilation environments.
@genixpro

genixpro commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@Giszmo The screen-center drift and flatter wide-map view are addressed in a5a9491. The map position at the center of the 2D view stays anchored throughout the single smooth transition. The 512 × 64 view is now much flatter (about 19.5° here), and the surface at the focus faces the camera so its projected tiles stay close to square. The geometry and picking code share that anchor, with regression coverage for the transition and rectangular maps.

Here are actual OpenGL checkerboard renders from that commit, width × height:

64 × 512 512 × 64
64 × 512 circular torus 512 × 64 flatter circular torus

We compared an elliptical cross-section and kept the circular shape after visual testing. The 64 × 512 case still has a very small inner opening and substantial variation in tile area around the tube; readability at the camera-facing focus is the priority.

Master is now merged through f50ab27 in 708a65d, with build/CI conflicts resolved. Local OpenGL and software rendering checks, geometry/picking sanitizer checks, all 170 unit tests, the standalone tests, and the terrain, gradient and team-statistics regressions pass. Fresh Linux/Windows CI will also check the software-only build. Automatic folding remains off by default in the main Settings menu, with G switching available. The PR is ready for review again; native Wayland playtesting is still outstanding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants